#![allow(non_snake_case)]
use leptos::{ev, html, prelude::*};
use shq_common::prelude::Size;
use thaw_utils::{ArcOneCallback, BoxOneCallback, ComponentRef, Model};

use crate::ValidType;

#[component]
pub fn TextArea(
    #[prop(optional, into)] value: Model<Option<String>>,
    #[prop(optional, into)] allow_value: Option<ArcOneCallback<String, bool>>,
    #[prop(optional, into)] on_change: Option<BoxOneCallback<Option<String>>>,
    #[prop(optional, into)] placeholder: MaybeProp<String>,
    #[prop(optional, into)] on_focus: Option<BoxOneCallback<ev::FocusEvent>>,
    #[prop(optional, into)] on_blur: Option<BoxOneCallback<ev::FocusEvent>>,
    #[prop(optional, into)] disabled: MaybeProp<bool>,
    #[prop(optional, into)] size: MaybeProp<Size>,
    #[prop(default = 100.into(),into)] height: MaybeProp<u16>,
    #[prop(optional, into)] valid_type: MaybeProp<ValidType>,
    #[prop(optional)] comp_ref: ComponentRef<TextAreaRef>,
    #[prop(default=true.into(), into)] border: MaybeProp<bool>,
    #[prop(optional)] is_init_focus: bool,
) -> impl IntoView {
    let on_input = move |ev| {
        let input_value = event_target_value(&ev);
        if let Some(allow_value) = allow_value.as_ref() {
            if !allow_value(input_value.clone()) {
                return;
            }
        }
        let val=if input_value.is_empty() {None} else {Some(input_value)};
        value.set(val.clone());
        if let Some(on_change) = on_change.as_ref() {
            on_change(val.clone());
        }
    };
    let is_focus = RwSignal::new(false);
    let on_internal_focus = move |ev| {
        is_focus.set(true);
        if let Some(on_focus) = on_focus.as_ref() {
            on_focus(ev);
        }
    };
    let on_internal_blur = move |ev| {
        is_focus.set(false);
        if let Some(on_blur) = on_blur.as_ref() {
            on_blur(ev);
        }
    };

    let textarea_ref = NodeRef::<html::Textarea>::new();
    textarea_ref.on_load(move |_| {
        comp_ref.load(TextAreaRef { textarea_ref });
    });
     Effect::new(
        move || {
            if let Some(textarea_el) = textarea_ref.get_untracked() {
                if is_init_focus {
                    _ = textarea_el.focus();
                }
            }
        }
    );
    let size_class=move||size.get().map(|s|s.to_class("input")).unwrap_or("".to_string());
    let combined_classes = {
        if border.get().unwrap_or_default() {
            let color = valid_type.get().map(|vt| vt.as_color_str()).unwrap_or("");
            if color.is_empty() {
                format!("textarea textarea-bordered {}",size_class())
            } else {
                format!("textarea textarea-bordered textarea-{} {}",color,size_class())
            }
        } else {
            "outline-0 border-0 w-full ml-1 mr-1 bg-inherit".to_owned()
        }
    };
    view! {
        <textarea
            prop:value=move || {
                value.get().unwrap_or_default()
            }
            on:input=on_input
            on:focus=on_internal_focus
            on:blur=on_internal_blur
            class=combined_classes
            style:height=move || format!("{}px",height.get().unwrap_or_default())
            disabled=move || disabled.get()
            placeholder=placeholder.get()
            node_ref=textarea_ref
        />
    }
}

#[derive(Clone)]
pub struct TextAreaRef {
    textarea_ref: NodeRef<html::Textarea>,
}

impl TextAreaRef {
    pub fn focus(&self) {
        if let Some(textarea_el) = self.textarea_ref.get_untracked() {
            _ = textarea_el.focus();
        }
    }

    pub fn blur(&self) {
        if let Some(textarea_el) = self.textarea_ref.get_untracked() {
            _ = textarea_el.blur();
        }
    }
}
